﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Configuration;
using System.IO;

namespace Log
{
    /// <summary>
    /// 日志消息处理
    /// </summary>
    public class Logger
    {
        private static object mylock = new object();
        private static Queues _myQueues;
        private static bool WriterFlag = false;
        private static Thread _LogWriteThread;
        #region init
        /// <summary>
        /// 队列集合
        /// </summary>
        /// <returns></returns>
        private static Queues MyQueues
        {
            get
            {
                if (_myQueues == null)
                    lock (mylock)
                    {
                        if (_myQueues == null)
                        {
                            _myQueues = new Queues();
                        }
                    }
                return _myQueues;
            }
        }
        /// <summary>
        /// 日志写线程
        /// </summary>
        private static Thread LogWriteThread
        {
            get
            {
                if (_LogWriteThread == null)
                {
                    lock (mylock)
                    {
                        if (_LogWriteThread == null)
                        {
                            _LogWriteThread = new Thread(new ThreadStart(DoWork));
                            if (_LogWriteThread.ThreadState != ThreadState.Running)
                                _LogWriteThread.Start();
                        }
                    }
                }
                return _LogWriteThread;
            }
        }
        #endregion
        #region Message
        /// <summary>
        /// 
        /// </summary>
        /// <param name="Name"></param>
        /// <param name="Status"></param>
        /// <param name="Message"></param>
        public static void Writer(string Name, QueueStatus Status, string Message)
        {
            MessageReceiver(Name, Status, Builder(Name, Message));
        }
        public static void Writer(string Message)
        {
            Writer("defalut", QueueStatus.Close, Message);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="Name"></param>
        /// <param name="Status"></param>
        /// <param name="Message"></param>
        public static void Writer(string Name, QueueStatus Status, Exception Message)
        {
            MessageReceiver(Name, Status, Builder(Name, Message));
        }
        public static void Writer(Exception Message)
        {
            Writer("defalut", QueueStatus.Close, Message);
        }
        #endregion
        #region Message string builder
        /// <summary>
        /// 消息字符串
        /// </summary>
        /// <param name="Message"></param>
        /// <returns></returns>
        private static string Builder(string QueueName, string Message)
        {
            string MessageString = string.Empty;
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("*****************************************************************");
            sb.AppendLine("QueueName：" + QueueName);
            sb.AppendLine("Datatime：" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"));
            sb.AppendLine("Message：" + Message);
            MessageString = sb.ToString();
            sb.Clear();
            return MessageString;
        }
        /// <summary>
        /// 异常字符串
        /// </summary>
        /// <param name="Message"></param>
        /// <returns></returns>
        private static string Builder(string QueueName, Exception Message)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("*****************************************************************");
            sb.AppendLine("QueueName：" + QueueName);
            sb.AppendLine("Datatime：" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"));
            sb.AppendLine("ErrorMessage：" + Message.Message);
            sb.AppendLine("Source：" + Message.Source);
            sb.AppendLine("StackTrace：" + Message.StackTrace);
            sb.AppendLine("TargetSite：" + Message.TargetSite);
            string MessageString = sb.ToString();
            sb.Clear();
            return MessageString;
        }
        #endregion
        #region 日志消息接收器
        /// <summary>
        /// 把处理的信息写入到队列集合
        /// </summary>
        /// <param name="Name"></param>
        /// <param name="Status"></param>
        /// <param name="Message"></param>
        private static void MessageReceiver(string Name, QueueStatus Status, string Message)
        {
            IQueueInfo MyQueue = null;
            lock (MyQueues)
            {
                //判断队列是否存在
                if (MyQueues.Exists(Name))
                {
                    //获取队列实例
                    MyQueue = MyQueues.GetQueue(Name);
                }
                else
                {
                    //新建队列
                    MyQueue = MyQueues.New();
                    MyQueue.Name = Name;
                }
                //队列的状态
                MyQueue.Status = Status;
                //把处理的信息写入队列
                MyQueue.MessageQueue.Enqueue(Message.ToString());
                #region 队列溢出处理
                //队列里的数量不能大于156W，再多了就会溢出。
                if (MyQueue.MessageQueue.Count >= 1560000)
                {
                    if (MyQueue.Status == QueueStatus.Open)
                    {
                        MyQueue.Status = QueueStatus.Close;
                        MyQueue.Name = MyQueue.Name + "_Out";
                    }
                }
                #endregion
            }
            //启动日志写线程
            StartLogWriteThread();
        }
        #endregion
        #region 日志写线程
        /// <summary>
        /// 日志的写线程
        /// </summary>
        private static void StartLogWriteThread()
        {
            #region 启动写日志线程
            WriterFlag = true;
            if (LogWriteThread.ThreadState == ThreadState.Stopped)
            {
                _LogWriteThread = null;
            }
            #endregion
        }
        /// <summary>
        /// 日志写线程
        /// </summary>
        private static void DoWork()
        {
            while (WriterFlag)
            {
                lock (MyQueues)
                {
                    foreach (var item in MyQueues.GetQueues())
                    {
                        if (item.MessageQueue.Count <= 0)
                        {
                            MyQueues.Remove(item);
                            continue;
                        }
                        while (item.MessageQueue.Count > 0)
                        {
                            WriteToFile(item.MessageQueue.Dequeue());
                        }
                        MyQueues.Remove(item);
                    }
                }
                #region 结束线程；队列集合为
                if (MyQueues.Count <= 0)
                {
                    WriterFlag = false;
                    LogWriteThread.Abort();
                }
                #endregion
            }
        }
        #endregion
        #region IO File
        /// <summary>
        /// 把日志信息写入到文件
        /// </summary>
        /// <param name="Message"></param>
        private static void WriteToFile(string Message)
        {
            try
            {
                lock (mylock)
                {
                    string FilePath = ConfigurationManager.AppSettings["LogFilePath"].ToString() + "\\Log";
                    string FileName = "Log - " + DateTime.Now.ToString("yyyy-MM-dd") + ".log";
                    StreamWriter sw;
                    if (!Directory.Exists(FilePath))
                        Directory.CreateDirectory(FilePath);
                    sw = new StreamWriter(FilePath + "\\" + FileName, true, Encoding.UTF8);
                    sw.WriteLine(Message);
                    sw.Flush();

                    if (sw != null)
                    {
                        sw.Flush();
                        sw.Close();
                        sw.Dispose();
                        sw = null;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.Out.WriteLine(ex);
            }
        }
        #endregion
    }
}
